# coding:utf-8
"""
JWT 令牌验证
OAuth2
"""
from datetime import datetime, timedelta, timezone
from typing import Union

from fastapi import Depends, Request, status, HTTPException
from fastapi.security import SecurityScopes
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext

from app.config.settings import settings
from app.models import Admin

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def verify_password(plain_password, hashed_password):
    """
    密码校验
    :param plain_password: 用户输入的密码
    :param hashed_password: 数据库密码
    :return: Boolean
    """
    check = pwd_context.verify(plain_password, hashed_password)
    if check:
        return True
    else:
        return False


def get_password_hash(password):
    """
    密码加密
    :param password:
    :return: 加密后的密码
    """
    return pwd_context.hash(password)


OAuth2 = OAuth2PasswordBearer(tokenUrl="token")


# OAuth2 = OAuth2PasswordBearer(settings.SWAGGER_UI_OAUTH2_REDIRECT_URL, scheme_name="User",
#                               scopes={"is_admin": "超级管理员", "not_admin": "普通管理员"})


def create_access_token(data: dict):
    """
    创建 token
    :param data:
    user_id
    username
    :return: JWT
    """
    token_data = data.copy()
    # token超时时间
    expire = datetime.utcnow() + timedelta(minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES)
    # 向jwt加入超时时间
    token_data.update({"exp": expire})
    # jwt加密
    jwt_token = jwt.encode(token_data, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM)

    return jwt_token


async def check_auth(token: str = Depends(OAuth2)):
    """
    权限验证
    :param token:
    :param req:
    :param security_scopes: 权限域
    :return:
    """
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效凭证",
        headers={"WWW-Authenticate": f"Bearer {token}"},
    )
    # ---------验证JWT token-----------
    try:
        # token解密
        payload = jwt.decode(
            token,
            settings.JWT_SECRET_KEY,
            algorithms=[settings.JWT_ALGORITHM]
        )
        if payload:
            # 用户ID
            user_id = payload.get("user_id", None)
            # 用户类型
            user_type = payload.get("is_super", None)
            # 无效用户信息
            if user_id is None or user_type is None:
                raise credentials_exception
        else:
            raise credentials_exception
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="凭证已证过期",
            headers={"WWW-Authenticate": f"Bearer {token}"},
        )

    except JWTError:
        raise credentials_exception

    # ---------------------------------------验证权限-------------------------------------------------------------------
    # 查询用户是否真实有效、或者已经被禁用
    check_user = await Admin().get_or_none(id=user_id)
    if not check_user or check_user.status != 0:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户不存在或已经被禁用!",
            headers={"WWW-Authenticate": f"Bearer {token}"},
        )

    # 单次请求信息保存
    request.state.admin_id = uid
    request.state.role_ids = [int(i) for i in mapping.get('role_ids').split(',')]
    request.state.username = mapping.get('username')
    request.state.nickname = mapping.get('nickname')
    return check_user


DependAuth = Depends(check_auth)